package main

import (
	"fmt"
	"os/exec"
	"os"
	"encoding/json"
	"time"
	"strings"
	"net"
	"github.com/influxdata/influxdb/client/v2"
	"strconv"
)

var Ip = getIp()

type Configuration struct {
  Port            int
	Url             string
	DB              string
	MasterInstructions    []string
        MinionInstructions    []string
        Master          string
	Freq            int
	Username        string
	Password        string
}

func execCommand(param string) (string, error){
	f, err := exec.Command("/bin/sh", "-c", param).Output()
	if err != nil {
		return "", err
	}
	return string(f), err
	// storage(s)
}

func housekeep(conf Configuration) {
	var cmdRess []string
        var aliveRess []string
        var instructions []string
        if conf.Master == "Y" {
                instructions = conf.MasterInstructions
        } else {
                instructions = conf.MinionInstructions
        }
	for _, ins := range instructions{
		cmdRes, err := execCommand(ins)
                insRes := strings.Fields(ins)
		if err != nil {
                        aliveRess = append(aliveRess, insRes[6] + " N")
			continue
		}
		// writePoints(conf, cmdRes)
                aliveRess = append(aliveRess, insRes[6] + " Y")
		cmdRess = append(cmdRess, cmdRes)
	}
	writePoints(conf, cmdRess, aliveRess)
}

func getConfiguration() Configuration {
	file, _ := os.Open("advisor-conf.json")
	decoder := json.NewDecoder(file)
	configuration := Configuration{}
	err := decoder.Decode(&configuration)
	if err != nil {
		fmt.Println("error:", err)
		os.Exit(1)
	}

	return configuration
}

func getIp() string {

	addrs, err := net.InterfaceAddrs()

	if err != nil {
		fmt.Println("error:", err)
		os.Exit(1)
	}

	var ip string

	for _, address := range addrs {
		// 检查ip地址判断是否回环地址
		if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
			if ipnet.IP.To4() != nil {
				// fmt.Println(ipnet.IP.String())
				ip = ipnet.IP.String()
				break
			}
		}
	}

	return ip
}


func writePoints(conf Configuration, cmdRess []string, aliveRess []string) {
	// Make client
	// TODO fix joint
	c, err := client.NewHTTPClient(client.HTTPConfig{
		Addr: conf.Url,
	})
	if err != nil {
		fmt.Println("Error creating InfluxDB Client: ", err.Error())
	}
	defer c.Close()

	// Create a new point batch
	bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
		Database:  conf.DB,
		Precision: "s",
	})
        
        for _, aliveRes := range aliveRess {
               aliveArray := strings.Fields(aliveRes)
               aliveTags := map[string]string{"host_id": Ip, "container_name": aliveArray[0]}
               aliveFields := map[string]interface{}{
                       "value":   aliveArray[1],
               }
               alivePt, err := client.NewPoint("process/alive_status", aliveTags, aliveFields, time.Now())
               if err != nil {
                        fmt.Println("Error: ", err.Error())
               }
               bp.AddPoint(alivePt)

        }

	for _, cmdRes := range cmdRess {
                //fmt.Println("cmdRes:", cmdRes)
		psRes := strings.Fields(cmdRes)
		// Create a point and add to batch
		//pid, err := strconv.ParseFloat(psRes[0], 64)
		//cpu, err := strconv.ParseFloat(psRes[2], 64)
		cpu, err := strconv.ParseFloat(psRes[2], 64)
		mem, err := strconv.ParseFloat(psRes[3],  64)
		tags := map[string]string{"type" : "process", "host_id": Ip, "container_name": psRes[1]}
		fields := map[string]interface{}{
			//"pid":   pid,
			"value":   cpu,
			//"mem":   mem,
		}
		fields2 := map[string]interface{}{
                        "value":   mem,
                }
		pt, err := client.NewPoint("process/cpu_usage_rate", tags, fields, time.Now())
		pt2, err := client.NewPoint("process/memory_usage_rate", tags, fields2, time.Now())
		if err != nil {
			fmt.Println("Error: ", err.Error())
		}
		// fmt.Println(pt)
		bp.AddPoint(pt)
                bp.AddPoint(pt2)
	}

	// Write the batch
	err = c.Write(bp)
	if err!=nil {
		fmt.Println(err)
	}
}


func main() {
	conf := getConfiguration()
	for {
		go housekeep(conf)
		time.Sleep(time.Duration(conf.Freq) * time.Second)
	}
}
